/**
 * @file gjson_object.c
 * @brief json object
 * @author JakeYang <add358@gmail.com>
 * @version 0.1
 * @date 2016-03-01
 */

#include "gjson_object.h"
#include "gjson_value.h"

static GJsonObject *g_json_object_new();
static gboolean g_json_object_insert(GJsonObject *obj, gchar *key, GJsonValue *v);
static void _g_json_object_print(gpointer key, gpointer v, gpointer t);
static void g_json_object_print_index(GString *t, gint level);

void _g_json_object_print(gpointer key, gpointer v, gpointer t)
{
    g_string_append(((GJsonText *)t)->str, "\n");
    g_json_object_print_index(((GJsonText *)t)->str, ((GJsonText *)t)->level);
    g_string_append_printf( ((GJsonText *)t)->str, "%s:", (gchar *)key);
    g_json_value_print(v, t);
}

inline gboolean g_json_object_insert(GJsonObject *obj, gchar *key, GJsonValue *v)
{
    return g_hash_table_insert(obj, key, v);
}

inline GJsonObject *g_json_object_new()
{
    return g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_json_value_free);
}

GJsonObject *g_json_object_parse(GJsonData *d)
{
    GJsonObject *obj = g_json_object_new();
    gchar *key = NULL;
    GJsonValue *value = NULL;

    if (!_equal_char(d, '{')) {
        goto gjson_object_parse_failed;
    }
    _forward(d, 1);

    for (_skip(d); !_equal_char(d, '}'); _skip(d)) {
        key = g_json_data_get_str(d);
        if (NULL == key) {
            goto gjson_object_parse_failed;
        }

        _skip(d);
        if (!_equal_char(d, ':')) {
            g_free(key);
            goto gjson_object_parse_failed;
        }
        _forward(d, 1);

        _skip(d);
        value = g_json_value_parse(d);
        if (NULL == value) {
            g_free(key);
            goto gjson_object_parse_failed;
        }

        g_json_object_insert(obj, key, value);

        _skip(d);
        if (_equal_char(d, ',')) {
            _forward(d, 1);
        }
    }

    _forward(d, 1);
    return obj;

gjson_object_parse_failed:
    g_json_object_free(obj);
    return NULL;
}

inline void g_json_object_print_index(GString *t, gint level)
{
    while(level--) {
        g_string_append(t, "\t");
    }
}

void g_json_object_print(GJsonObject *obj, GJsonText *t)
{
    if (t->level > 0) {
        g_json_object_print_index(t->str, t->level-1);
    }

    g_string_append(t->str, "{");
    ++(t->level);
    g_hash_table_foreach(obj, _g_json_object_print, t);
    g_string_append(t->str, "\n");
    g_json_object_print_index(t->str, t->level-1);
    g_string_append(t->str, "}");
    --(t->level);
}

inline void g_json_object_free(GJsonObject *obj)
{
    g_return_if_fail(("gjson object free", obj != NULL));
    g_hash_table_destroy(obj);
}

inline GJsonValue *g_json_object_get_value(GJsonObject *obj, const gchar *str, GJsonType type, GError **err)
{
    GJsonValue *v = g_hash_table_lookup(obj, str);
    if (NULL == v || v->type != type) {
        if (err) {
            *err = g_error_new(g_quark_from_string("GJSON"), type, "Get %s value failed", str);
        }
        return NULL;
    }
    return v;
}
